package main

import (
	"bufio"
	"flag"
	"fmt"
	"io"
	"net"
	"os"
	"strings"
)

const (
	STRING  = '+'
	ERROR   = '-'
	INTEGER = ':'
	BULK    = '$'
	ARRAY   = '*'
)

type RESP struct {
	reader *bufio.Reader
}

func NewResp(rd io.Reader) *RESP {
	return &RESP{reader: bufio.NewReader(rd)}
}

type Value struct {
	typ   string
	str   string
	num   int
	bulk  string
	array []Value
}

var port int

var Handlers = map[string]func([]string) string{
	"PING": ping,
}

// 读 -> 处理 -> 写
func main() {
	flag.IntVar(&port, "p", 6379, "监听端口")
	flag.Parse()

	fmt.Println(fmt.Sprintf("Listening on port:%v", port))
	l, err := net.Listen("tcp", fmt.Sprintf(":%v", port))
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	conn, err := l.Accept()
	if err != nil {
		fmt.Println(err)
		os.Exit(1)
	}
	defer conn.Close()

	for {
		resp := NewResp(conn)
		value, err := resp.Read()
		if err != nil {
			fmt.Println(err)
			os.Exit(1)
		}
		if value.typ != "array" {
			fmt.Println("Invalid request, expected array")
			continue
		}

		if len(value.array) == 0 {
			fmt.Println("Invalid request, expected array length > 0")
			continue
		}

		command := strings.ToUpper(value.array[0].bulk)
		args := Values2Strings(value.array[1:])
		handler, ok := Handlers[command]
		if !ok {
			fmt.Println("Invalid command: ", command)
			conn.Write(Value{typ: "error", str: "Invalid command"}.Marshal())
			continue
		}
		res := String2Value(handler(args))
		_, err = conn.Write(res.Marshal())
		if err != nil {
			return
		}
	}
}

func ping(args []string) string {
	if len(args) == 0 {
		return "PONG"
	}
	return args[0]
}
